package com.example.guarding_jc;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import android.telephony.*;

public class Guarding_JC extends ListActivity{
	public final static String SERVER_IP = "82.130.7.116";
	public final static int SERVER_PORT = 8080; 
	public final static String URL = "http://" + SERVER_IP + ":" + SERVER_PORT + "/HelloWS/rest/server/";
	
	public static TosendDataSource datasource;
	
	//private ListView pendingListView;
	
	private IsoDep isoDep;				//Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations on a Tag. 
	private NfcAdapter mNfcAdapter;
	public static String tag_uid;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.i("Debug: onCreate: ", " is called");
		setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
	
		setContentView(R.layout.activity_guarding__jc);
		
        // Check for available NFC Adapter
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter == null){
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        } 
        
        //list all the pending data
        datasource = new TosendDataSource(this);
        datasource.open();
	}

	/*
	 * When the "Show pending list" is pressed
	 */
	public void onShowPendingListClick(View view){
		List<DBEntry> values = datasource.getAllPendingScans();
		ArrayAdapter<DBEntry> adapter = new ArrayAdapter<DBEntry>(this, android.R.layout.simple_list_item_1, values);
		
		setListAdapter(adapter);
	}
	
	public void onShowLogClick(View view){
		//Toast.makeText(this, "on show log click", Toast.LENGTH_LONG).show();
		//send command to tag to read Log
		List<String> entries = new ArrayList<String>();
		Log.i("on show log click ", "is clicked");
		//ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, textViewResourceId)
		byte[] commandApdu = {(byte)0x12, (byte)0x00};
		try{
			while(true){
				byte[] log = isoDep.transceive(commandApdu);
				
				//convert this hex string to ascii characters

				//String log_str = Utility.toHexString(log);
				int len = 0;
				String log_str = "";
				for (int i = 0; i < 6; i++){
					//log_str += log[i] + " ";
					len += (int)log[i];
				}
				
				log_str += "HMAC = " + Utility.toHexString(Utility.extractMac(log)) + "\n";
				log_str += "Challenge = " + Utility.toHexString(Utility.extractChallenge(log)) + "\n";
				log_str += "Sequence = " + Utility.toHexString(Utility.extractSequence(log)) + "\n";
				log_str += "UID = " + Utility.toHexString(Utility.extractUID(log)) + "\n";
				log_str += "IMEI = " + new String(Utility.extractIMEI(log), Charset.forName("US-ASCII")) + "\n";
				log_str += "Time = " + new String(Utility.extractTime(log), Charset.forName("US-ASCII")) + "\n";
				
				Log.i("log of chars: ", log_str);
				//add to the list of entries

				/*int len = 0;
				for (int i = 0; i < 6; i++){
					len += (int)log[i];
				}*/
				
				Log.i("len of the entry is", len + "");
				Log.i("entry: ", log_str);
				//entries.add(log_str.substring(0, (6 + len)*2));
				entries.add(log_str);
				if (log[6 + len] == (byte)0x00 && log[7 + len] == (byte)0x00)
					break;
			}
			ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, entries);
			setListAdapter(adapter);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		//display the data
	}
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_guarding__jc, menu);
		return true;
	}
	
	@Override
	public void onResume(){
		Log.i("Debug: onResume: ", " is called");
		super.onResume();
		
		//pending intent
        IntentFilter [] tagFilters = new IntentFilter[]{new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED)};
		
		if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())){
			processIntent(getIntent());
		}

	}
	
	public void processIntent(Intent intent){
		Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
		byte[] id = tagFromIntent.getId();
		tag_uid = Utility.toHexString(id);
		isoDep = IsoDep.get(tagFromIntent);
		
		try{
			isoDep.connect();
			isoDep.setTimeout(300000); //The maximum time that phone waits for the tag is 5000 milisecon 
			new MessageExchangeHelper().execute();
		}	
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	@Override
	public void onNewIntent(Intent intent){
		Log.i("Debug: onNewIntent: ", " is called");
		setIntent(intent);
	}
	
	@Override
	public void onPause() {
	    super.onPause();
	    Log.i("Debug: onPause: ", " is called");
	   // mNfcAdapter.disableForegroundDispatch(this);
	}
	
	
	private class MessageExchangeHelper extends AsyncTask<String, Void, String>{
		@Override
	    protected String doInBackground(String...params ) {
			try{
				//if internet connection is available, connect to server to get the challenge
				Log.i("do in background: ", " is called");
			
				byte[] bChallenge = null;
				String curTime = Utility.getCurrentTime();
				
				byte[] currentTime = curTime.getBytes();
				
				byte[] IMEI = getIMEI().getBytes();
				
				if (isNetworkAvailable() == true){
					Log.i("Check network ", "available");
					String challengeURL = URL + "n/" + tag_uid;
					String challenge = Utility.sendToServer(challengeURL);
					bChallenge = Utility.toByteArray(challenge);
				}
				
				ChallengeCommand cmd;
				if (bChallenge == null || bChallenge.length == 0) 
					cmd = new ChallengeCommand(IMEI, currentTime);
				else
					cmd = new ChallengeCommand(bChallenge, IMEI, currentTime);
		
				byte[] cmdArr = cmd.toByteArray();
				
				byte[] tagResponse = null;
				
				tagResponse = Utility.sendToTag(isoDep, cmdArr);
				Log.i("response from the tag: ", Utility.toHexString(tagResponse));
				
				//process the tag's response
				//check the Internet connection again before sending response to the server
				if (isNetworkAvailable() == true){
					byte[] Mac = Utility.extractMac(tagResponse);
					byte[] sequence = Utility.extractSequence(tagResponse);
					byte[] challenge = Utility.extractChallenge(tagResponse);
					byte[] uid = Utility.extractUID(tagResponse);
					byte[] imei = Utility.extractIMEI(tagResponse);
					byte[] time = Utility.extractTime(tagResponse);
					
					String responseURL = URL + "tagResponse/" + tag_uid + "/" + Utility.toHexString(Mac) + "/"
											 + Utility.toHexString(sequence) + "/" + Utility.toHexString(challenge) + "/"
											 + Utility.toHexString(imei) + "/" + Utility.toHexString(time);
					
					String serverResponse = Utility.sendToServer(responseURL);
					
					
					/*String mime = "application/Guarding_JC";
					//payload
					byte[] payload = {(byte)0x70, (byte)0x61, (byte)0x79, (byte)0x6C, (byte)0x6F, (byte)0x61, (byte)0x64};
					//NdefRecord record = new NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE, mime.getBytes(), null, payload);
					NdefRecord record = NdefRecord.createMime(mime, payload);
					NdefMessage ndef = new NdefMessage(new NdefRecord[]{record});
					isoDep.transceive(ndef.toByteArray());
					*/
					//////////////////////////////////
					Log.i("server response: ", serverResponse);
					return serverResponse;
				}
				else{
					//insert to the db
					Utility.insertIntoDB(tag_uid, datasource, tagResponse);
					return "No Internet connection. This scan has been locally stored on the phone";
				}
			}
			catch(Exception e){
				e.printStackTrace();
				return "";
			}
		}
		
		@Override
	    protected void onPostExecute(String result) {
			Log.i("Debug: onPostExecute: ", " is called");
			ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 400);
			tg.startTone(ToneGenerator.TONE_CDMA_ABBR_ALERT);
		}	
	}
	
	public boolean isNetworkAvailable(){
		ConnectivityManager conManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo activeNetworkInfor = conManager.getActiveNetworkInfo();
		return activeNetworkInfor != null && activeNetworkInfor.isConnected();
	}
	
	public String getIMEI(){
		TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
		String device_id = tm.getDeviceId();
		return device_id;
	}
}
